package cn.sylinx.web;

import java.lang.reflect.Modifier;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.sylinx.web.auth.RequestAuth;
import cn.sylinx.web.log.GLog;
import cn.sylinx.web.map.GetRequestMapping;
import cn.sylinx.web.map.RequestMapping;
import cn.sylinx.web.template.velocity.VelocityRequestMapping;
import cn.sylinx.web.util.PackageUtil;
import cn.sylinx.web.util.StringUtil;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CookieHandler;
import io.vertx.ext.web.handler.SessionHandler;
import io.vertx.ext.web.handler.StaticHandler;
import io.vertx.ext.web.sstore.LocalSessionStore;

public class HttpVerticle extends AbstractVerticle {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	private HttpServer server;

	/**
	 * 加载路径映射
	 * 
	 * @param router
	 * @param mappingPackge
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private void loadMappings(Router router, String mappingPackge)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException {

		Set<String> clzSet = PackageUtil.getPackageClass(mappingPackge);

		Class<?> clz = null;

		for (String item : clzSet) {

			clz = Class.forName(item);

			// 不是接口、不是抽象类、继承自RequestMapping
			if (!clz.isInterface() && !Modifier.isAbstract(clz.getModifiers())
					&& RequestMapping.class.isAssignableFrom(clz)) {

				RequestMapping rm = (RequestMapping) clz.newInstance();
				Route route = router.route(rm.path()).blockingHandler(rm.handle(), false)
						.failureHandler(rm.failureHandler());

				HttpMethod[] methods = rm.method();
				for (HttpMethod method : methods) {
					route.method(method);
				}
			}

		}
	}

	/**
	 * 
	 * @param router
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private void loadRequestAuths(Router router, String authPackage)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException {

		Set<String> clzSet = PackageUtil.getPackageClass(authPackage);

		Class<?> clz = null;

		for (String item : clzSet) {

			clz = Class.forName(item);

			// 不是接口、不是抽象类、继承自RequestMapping
			if (!clz.isInterface() && !Modifier.isAbstract(clz.getModifiers())
					&& RequestAuth.class.isAssignableFrom(clz)) {
				RequestAuth ra = (RequestAuth) clz.newInstance();
				router.route(ra.path()).handler(ra.authHandler());
			}
		}
	}

	@Override
	public void start() throws Exception {

		GLog.info("http server starting, HttpVerticle: {}, ClassLoader: {}", this, this.getClass().getClassLoader());

		// 获取运行参数
		JsonObject cfg = config();
		int httpPort = cfg.getInteger("httpPort");
		String mappingPackges = cfg.getString("mappingPackges");
		String authPackages = cfg.getString("authPackages");

		// 创建http服务
		server = vertx.createHttpServer();

		// 获取请求路由
		Router router = Router.router(vertx);

		// 添加cookie处理
		router.route().handler(CookieHandler.create());
		
		// 添加session处理
		router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));

		// 处理body
		router.route().handler(BodyHandler.create());
		
		// 加载认证
		if (StringUtil.isNotBlank(authPackages)) {
			String[] pkgs = authPackages.split(",");
			for (String pkg : pkgs) {
				loadRequestAuths(router, pkg);
			}
		}

		// 加载路径映射
		if (StringUtil.isNotBlank(mappingPackges)) {
			String[] pkgs = mappingPackges.split(",");
			for (String pkg : pkgs) {
				loadMappings(router, pkg);
			}
		}

		// 添加系统默认映射
		loadDefault(router);

		// 监听端口
		server.requestHandler(router::accept).listen(httpPort);

	}

	/**
	 * 加载默认配置
	 * 
	 * @param router
	 */
	private void loadDefault(Router router) {

		// 默认加载velocity模板
		GetRequestMapping vrm = new VelocityRequestMapping();
		router.get(vrm.path()).handler(vrm.handle()).failureHandler(vrm.failureHandler());

		// 默认静态资源处理
		router.get("/static/*").handler(StaticHandler.create());
	}

	@Override
	public void stop() throws Exception {

		if (server != null) {
			server.close(result -> {

				if (result.succeeded()) {

					logger.info("server stop ok");

				} else {

					logger.error("server stop error,");
				}

			});
		}
	}

}
